#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <functional>
#include <unordered_map>
#include "nocopy.hpp"
#include "log.hpp"
#include "common.h"
#include "ThreadPool.hpp"
#include "InetAddr.hpp"

const static int defaultBacklog = 3;
using callback_t = function<void(int, InetAddr &)>;
using task_t = function<void()>;

class TcpServer : public noCopy
{
public:
    TcpServer(uint16_t port) : _port(port), _isrunning(false)
    {
    }

    void Init()
    {
        // 初始化监听套接字
        _listenSockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (_listenSockfd < 0)
        {
            lg.LogMessage(Fatal, "create sock failed, error code: %d, error string: %s", errno, strerror(errno));
            exit(sockError);
        }
        int opt = 1; // 表示启用

        // 设置套接字可绑定重复ip和port
        setsockopt(_listenSockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
        setsockopt(_listenSockfd, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt));

        lg.LogMessage(Debug, "create socket success, sockfd: %d", _listenSockfd);

        // 填充本地套接字地址结构体，并与套接字文件绑定
        struct sockaddr_in local;
        int len = sizeof(local);
        memset(&local, 0, len);
        local.sin_family = AF_INET;
        local.sin_addr.s_addr = htonl(INADDR_ANY);
        local.sin_port = htons(_port);

        if (bind(_listenSockfd, Convert(&local), len) != 0)
        {
            lg.LogMessage(Fatal, "bind sock failed, error code: %d, error string: %s", errno, strerror(errno));
            exit(bindError);
        }
        lg.LogMessage(Debug, "bind sock success");

        // 将监听套接字设置为监听状态
        if (listen(_listenSockfd, defaultBacklog) != 0)
        {
            lg.LogMessage(Fatal, "listen sock failed, error code: %d, error string: %s", errno, strerror(errno));
            exit(listenError);
        }
        lg.LogMessage(Debug, "listen sock success");
        ThreadPool<task_t>::GetInstance()->Start();
        // _funcs.insert(make_pair<string, callback_t>("DefaultService", std::bind(&DefaultService, this, placeholders::_1, placeholders::_2))); //在绑定函数时，必须写明函数的作用域
        _funcs.insert(make_pair<string, callback_t>("DefaultService", std::bind(&TcpServer::DefaultService, this, placeholders::_1, placeholders::_2))); 

    }

    void service(int sockfd)
    {
        // 从客户端接收消息，并向客户端回显消息
        char buffer[1024];
        while (true)
        {
            int n = read(sockfd, buffer, sizeof(buffer) - 1);
            if (n > 0)
            {
                buffer[n] = 0;
                std::cout << "get a message: " << buffer << std::endl;
                std::string echo_message = "server echo# ";
                echo_message += buffer;
                write(sockfd, echo_message.c_str(), echo_message.size());
            }
            else if (n == 0) // 表示读到了文件末尾（对端关闭了连接）
            {
                lg.LogMessage(Info, "client quit");
                break;
            }
            else
            {
                lg.LogMessage(Error, "read socket failed");
                break;
            }
        }
    }
    void Routine(int sockfd, InetAddr &addr)
    {
        _funcs["DefaultService"](sockfd, addr);

        close(sockfd);
    }

    void DefaultService(int sockfd, InetAddr &addr)
    {
        std::string service_list = "|";
        for (auto func : _funcs)
        {
            service_list += func.first;
            service_list += "|";
        }
        write(sockfd, service_list.c_str(), service_list.size());
        // std::cout << "send client a message: " << service_list << std::endl;
    }
    void Start()
    {
        _isrunning = true;
        while (_isrunning)
        {
            // 接受连接
            sockaddr_in peer;
            socklen_t len = sizeof(peer);
            int sockfd = accept(_listenSockfd, Convert(&peer), &len);
            if (sockfd < 0)
            {
                lg.LogMessage(Fatal, "accept sock failed, error code: %d, error string: %s", errno, strerror(errno));
                exit(acceptError);
            }
            lg.LogMessage(Debug, "accept a socket, sockfd: %d", sockfd);
            // v5版本 引入线程池
            task_t task = std::bind(&TcpServer::Routine, this, sockfd, InetAddr(peer));
            ThreadPool<task_t>::GetInstance()->Push(task);

        }
    }
    ~TcpServer()
    {
    }

private:
    uint16_t _port;
    bool _isrunning;   // 因为tcp服务器要维持连接状态，所以要记录服务器运行状态
    int _listenSockfd; // 监听套接字

    std::unordered_map<string, callback_t> _funcs; // 业务逻辑构建
};